/*
 * @Author: hongbin
 * @Date: 2023-06-10 20:05:26
 * @LastEditors: hongbin
 * @LastEditTime: 2023-06-23 19:35:11
 * @Description:乾为天
 */
import { FC } from "react";
import * as THREE from "three";
import { ThreeHelper } from "@/ThreeHelper";
import Layout from "@/components/Three/Layout";
// import { HideMaterial } from "@/shader/HideMaterial/material";

import * as TWEEN from "@tweenjs/tween.js";
import { HideMaterial } from "@/shader/HideMaterial/standardMaterial";
import { RoomEnvironment } from "../ThreeHelper/expand/RoomEnvironment";
import { TaiJiMaterial } from "@/shader/TaiJiMaterial/material";
import { UseTaiJIPictureMaterial } from "@/ThreeHelper/expand/UseTaiJIPictureMaterial/material";

interface IProps {}

const destroyEvent = [] as VoidFunction[];

const Index: FC<IProps> = () => {
    return (
        <Layout
            seoTitle={"乾为天"}
            init={init}
            destroy={() => destroyEvent.forEach((destroy) => destroy())}
        />
    );
};

export default Index;

async function init(helper: ThreeHelper) {
    helper.addStats();
    // helper.addAxis();
    helper.camera.position.set(0, 0, 15);
    helper.frameByFrame();
    helper.addGUI();
    // helper.useRoomEnvironment(true);

    helper.scene.environment?.dispose();
    const roomEnv = new RoomEnvironment();
    roomEnv.load = () => {
        const envRenderTarget = helper.pmremGenerator.fromScene(roomEnv, 0.02);
        const env = envRenderTarget.texture;

        helper.scene.environment = env;
        helper.scene.background = env;
    };

    const model = await helper.loadGltf("/models/qian.glb");
    const ani = await helper.loadGltf("/models/qian_ani.glb");

    helper.add(ani.scene);
    ani.scene.position.y = 3;
    ani.scene.position.x = 2;

    new QIAN_ANI(ani.scene);

    model.scene.position.x = -3;
    model.scene.position.z = -3;
    model.scene.position.y = 3;
    model.scene.rotateX(Math.PI / 2);
    ani.scene.rotateX(Math.PI / 2);
    ani.scene.position.y -= 3;
    ani.scene.position.x = 2;

    new QIAN(model.scene);

    helper.add(model.scene);

    helper.gui
        ?.add({ p: 0 }, "p", 0, 1)
        .onChange(({ p }) => {})
        .step(0.01);

    helper.animation(() => {
        TWEEN.update();
    });

    const mainLight = new THREE.PointLight("#f00", 3.0, 20);
    mainLight.position.set(1, 1, 3);
    ani.scene.add(mainLight);
    {
        const mainLight = new THREE.PointLight("#1900ff", 3.0, 20);
        mainLight.position.set(0, 0, 0);
        ani.scene.add(mainLight);
    }
}

class QIAN {
    横: THREE.Mesh;
    竖: THREE.Mesh;
    撇: THREE.Mesh;
    捺: THREE.Mesh;
    横弯: THREE.Mesh;

    constructor(model: THREE.Group) {
        this.横 = model.getObjectByName("横") as THREE.Mesh;
        this.竖 = model.getObjectByName("竖") as THREE.Mesh;
        this.撇 = model.getObjectByName("撇") as THREE.Mesh;
        this.捺 = model.getObjectByName("捺") as THREE.Mesh;
        this.横弯 = model.getObjectByName("横弯") as THREE.Mesh;
        this.init();
        model.traverse((v) => {
            if (v.type == "Mesh") {
                v.castShadow = true;
            }
        });
    }

    computeSize(mesh: THREE.Mesh) {
        const box = new THREE.Box3();
        box.setFromObject(mesh);
        return box.getSize(new THREE.Vector3());
    }

    tween(material: HideMaterial, delay = 0) {
        new TWEEN.Tween({ f: 0 })
            .to({ f: 1 }, 1000)
            .delay(delay)
            .start()
            .onUpdate(({ f }) => {
                material.uniforms.process.value = f;
            });
    }

    initMaterial(mesh: THREE.Mesh, axis: "x" | "y" | "z", delay = 0) {
        const material = new HideMaterial({
            axis: axis.charCodeAt(0) - 120,
            axisLength: this.computeSize(mesh)[axis],
            process: 0,
            color: new THREE.Color("#000"),
        });
        mesh.material = material;
        ThreeHelper.instance.gui
            ?.add({ f: 0 }, "f", 0, 1)
            .onChange((v) => {
                material.uniforms.process.value = v;
            })
            .step(0.01)
            .name(mesh.name);
        this.tween(material, delay);
    }

    init() {
        this.initMaterial(this.横, "x");
        this.initMaterial(this.竖, "z", 1000);
        this.initMaterial(this.横弯, "x", 2000);
        this.initMaterial(this.撇, "z", 3000);
        this.initMaterial(this.捺, "z", 4000);
    }
}

type Mesh = THREE.Mesh<THREE.BufferGeometry, THREE.MeshStandardMaterial>;

class QIAN_ANI {
    constructor(model: THREE.Group) {
        model.traverse((obj) => {
            if (obj.type == "Mesh") {
                const mesh = obj as Mesh;

                const index = +mesh.name[mesh.name.length - 1] - 1;
                mesh.material.opacity = 0;
                mesh.material.transparent = true;
                // 环
                if (mesh.name.indexOf("h") != -1) {
                    this.tween(mesh, index * 500);

                    const parent = model.getObjectByName(`空物体${index + 1}`);
                    if (parent) {
                        let speedZ = Math.random() * 0.001 * (3 - index);
                        let dir = 0.5 - Math.random() > 0 ? 1 : -1;
                        let count = 0;
                        mesh.onBeforeRender = () => {
                            parent.rotation.z -= speedZ * dir;
                            if (count++ % ((index + 1) * 100) == 0) {
                                dir *= -1;
                            }
                        };
                    }
                }
                // 球
                else if (mesh.name.indexOf("s") != -1) {
                    let speed = Math.random() * 0.06;
                    let count = 0;
                    this.iridescenceMaterial(mesh);
                    mesh.material.opacity = 0;
                    mesh.material.transparent = true;
                    this.tween(mesh, index * 200);
                    mesh.onBeforeRender = () => {
                        mesh.rotation.y -= speed;
                        if (count++ % 180 == 0) {
                            speed = Math.random() * 0.06;
                        }
                    };
                }
            }
        });
    }

    iridescenceMaterial(mesh: Mesh) {
        mesh.material.dispose();
        mesh.material = new THREE.MeshPhysicalMaterial({
            color: new THREE.Color("#000"),
            metalness: 1,
            thickness: 1,
            iridescence: 2,
            iridescenceIOR: 1.2,
        });
    }

    tween(
        mesh: THREE.Mesh<THREE.BufferGeometry, THREE.MeshStandardMaterial>,
        delay = 0
    ) {
        new TWEEN.Tween({ f: 0 })
            .to({ f: 1 }, 1000)
            .delay(4000 + delay)
            .start()
            .onUpdate(({ f }) => {
                mesh.material.opacity = f;
                mesh.material.alphaTest = f - 0.01;
            });
    }
}
